package com.sc.nft.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.sc.nft.annotation.UserLogin;
import com.sc.nft.annotation.WithoutSign;
import com.sc.nft.controller.request.*;
import com.sc.nft.controller.vo.BankCardVO;
import com.sc.nft.controller.vo.SandAccountVO;
import com.sc.nft.controller.vo.SandWithdrawRecordVO;
import com.sc.nft.dao.*;
import com.sc.nft.entity.*;
import com.sc.nft.entity.dto.UserAffirmDTO;
import com.sc.nft.entity.dto.sand.SmsDTO;
import com.sc.nft.entity.vo.BalanceVO;
import com.sc.nft.entity.vo.PaymentMethodVO;
import com.sc.nft.entity.vo.SandTransferRecordVO;
import com.sc.nft.enums.AccountStatusEnum;
import com.sc.nft.enums.PayChannelEnum;
import com.sc.nft.enums.RedisKeyEnum;
import com.sc.nft.enums.WalletChannelEnum;
import com.sc.nft.helper.LlPayHelper;
import com.sc.nft.helper.SandAccountHelper;
import com.sc.nft.pool.UserPool;
import com.sc.nft.service.*;
import com.sc.nft.sup.ErrorCode;
import com.sc.nft.sup.PageResult;
import com.sc.nft.sup.Result;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.map.HashedMap;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.util.UriUtils;
import springfox.documentation.annotations.ApiIgnore;

import javax.validation.Valid;
import java.io.IOException;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

@Slf4j
@RequiredArgsConstructor
@RestController
@RequestMapping("/pay/cloudAccount")
@Api(tags = "云账户接口")
public class CloudAccountController {

    private final SandAccountHelper sandAccountHelper;
    private final PayOrderService payOrderService;
    private final SandWithdrawRecordDao sandWithdrawRecordDao;
    private final UserInfoService userInfoService;
    private final UserInfoDao userInfoDao;
    private final StaticDataDao staticDataDao;
    private final WithdrawBankCardDao withdrawBankCardDao;
    private final SandTransferRecordService sandTransferRecordService;
    private final UserHfExtDao userHfExtDao;
    private final UserHnaExtService userHnaExtService;
    private final UserHnaExtDao userHnaExtDao;
    private final LlUserExtService llUserExtService;
    private final LlPayHelper llPayHelper;
    private final IdcardInfoDao idcardInfoDao;
    private final Redisson redisson;
    private final UserOrderAccountFlowDao userOrderAccountFlowDao;

    @ApiOperation(value = "提交开户", notes = "提交开户", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/openAccount", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result<List<PaymentMethodVO>> openAccount(@RequestBody @Valid OpenAccountRequest request) throws IOException {
        UserInfo user = UserPool.getUser();
        if (BooleanUtil.isTrue(user.getSandAccountOpen())) {
            return Result.fail("您已完成开户");
        }

        if (!user.getIsSm()) {
            return Result.fail("请先完成实名认证");

        }
        sandAccountHelper.sandOpenAccount(request.getCustomerOrderNo(), user, request.getSmsCode(), request.getSmsSerialNo(), request.getFrontImgNo(), request.getReverseImgNo());
        return Result.success();
    }


    @ApiOperation(value = "开户发送短信", notes = "开户发送短信", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/sms", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result<SmsDTO> getPaymentMethods() {
        UserInfo user = UserPool.getUser();
        if (BooleanUtil.isTrue(user.getSandAccountOpen())) {
            return Result.fail("您已完成开户");
        }
        return Result.success(sandAccountHelper.smsSend(user));
    }

    @ApiOperation(value = "签约协议", notes = "签约协议", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/signProtocol", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result<String> signProtocol() {
        UserInfo user = UserPool.getUser();
        if (BooleanUtil.isFalse(user.getSandAccountOpen())) {
            return Result.fail("您尚未完成开户");
        }
        if (BooleanUtil.isTrue(user.getSandFaceVerify())) {
            return Result.fail("您已完成签约");
        }
        return Result.success(sandAccountHelper.sign(user));
    }

    @ApiOperation(value = "上传身份证照片", notes = "上传身份证照片", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/upload", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result<Map> upload(@Valid UpLoadIdCardRequest request) {
        UserInfo user = UserPool.getUser();
        Map map = new HashedMap();
        map.put("data", sandAccountHelper.upload(user, request.getFileType(), request.getUploadFile()));
        return Result.success(map);
    }

    @ApiOperation(value = "关联银行卡", notes = "关联银行卡", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/relationBankCard", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result relationBankCard(@RequestBody @Valid BindBankCardRequest request) {
        UserInfo user = UserPool.getUser();
        if (BooleanUtil.isFalse(user.getSandAccountOpen())) {
            return Result.fail("您尚未完成开户");
        }
        sandAccountHelper.bindCard(user, request.getCardNo(), request.getCertificateNo(), request.getName(), request.getPhoneNo());
        return Result.success();
    }

    @ApiOperation(value = "注销", notes = "注销", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/cancel", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result<String> cancel() {
        UserInfo user = UserPool.getUser();
        if (BooleanUtil.isFalse(user.getSandAccountOpen())) {
            return Result.fail("您尚未完成开户");
        }
        return Result.success(sandAccountHelper.cancel(user));
    }

    @ApiOperation(value = "用户操作确认", notes = "用户操作确认", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/affirm", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result<String> affirm(@RequestBody UserAffirmDTO userAffirmDTO) {
        UserInfo user = UserPool.getUser();
        if (BooleanUtil.isFalse(user.getSandAccountOpen())) {
            return Result.fail("您尚未完成开户");
        }
        return Result.success(sandAccountHelper.affirm(user, userAffirmDTO));
    }


    @ApiOperation(value = "提现银行卡列表", notes = "提现银行卡列表", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/withdrawBankCardList", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result<List<BankCardVO>> withdrawBankCardList(@RequestBody WalletChannelRequest request) {
        UserInfo user = UserPool.getUser();
        List<WithdrawBankCard> byUserIdAndChannel = withdrawBankCardDao.getByUserIdAndChannel(UserPool.getUser().getId(), request.getChannel());
        for (WithdrawBankCard withdrawBankCard : byUserIdAndChannel) {
            withdrawBankCard.setBankCardNo("****" + withdrawBankCard.getBankCardNo().substring(withdrawBankCard.getBankCardNo().length() - 4));
        }
        return Result.successColl(byUserIdAndChannel, BankCardVO.class);
    }


    @ApiOperation(value = "解绑银行卡", notes = "解绑银行卡", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/discard", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result<BankCardVO> discard(@RequestBody @Valid IdRequest request) {
        UserInfo user = UserPool.getUser();
        if (BooleanUtil.isFalse(user.getSandAccountOpen())) {
            return Result.fail("您尚未完成开户");
        }
        sandAccountHelper.unbindCard(user, request.getId());
        return Result.success();
    }

    @ApiOperation(value = "查询衫德转账账户", notes = "查询衫德转账账户", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/getSandAccount", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result<SandAccountVO> getSandAccount() {
        UserInfo user = UserPool.getUser();
        if (BooleanUtil.isFalse(user.getSandAccountOpen())) {
            return Result.fail("您尚未完成开户");
        }
        SandAccountVO sandAccountVO = new SandAccountVO();
        sandAccountVO.setAccount(user.getSandMasterAccount());
        sandAccountVO.setImageUrl("https://cdn.gometa.com.cn/scnft/default/%E6%9D%89%E5%BE%B7%E9%92%B1%E5%8C%85%E5%85%85%E5%80%BC%E6%95%99%E7%A8%8B.jpg");
        sandAccountVO.setName(idcardInfoDao.getByUserIdAndIsPass(user.getId()).getName());
        return Result.success(sandAccountVO);
    }


    @ApiOperation(value = "查询衫德信息", notes = "查询衫德信息", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/getSandInfo", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result<String> getSandInfo() {
        UserInfo user = UserPool.getUser();
        return Result.success(sandAccountHelper.getSandInfo(user));
    }

    @ApiOperation(value = "查询余额", notes = "查询余额", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/getBalance", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result<BalanceVO> getBalance() {
        UserInfo user = UserPool.getUser();
        UserHfExt hfExt = userHfExtDao.findByUserId(user.getId());
        LlUserExt llUserExt = llUserExtService.getByUserId(user.getId());
        UserHnaExt hnaExt = userHnaExtDao.getByUserId(user.getId());
        BalanceVO balance = new BalanceVO();
        balance.setLlUnsettleAmount(userOrderAccountFlowDao.queryOrInit(user.getId(), PayChannelEnum.LL_PAY).
                getUnsettleAmount().setScale(2, BigDecimal.ROUND_DOWN).toPlainString());
        balance.setSandUnsettleAmount(userOrderAccountFlowDao.queryOrInit(user.getId(), PayChannelEnum.SAND).
                getUnsettleAmount().setScale(2, BigDecimal.ROUND_DOWN).toPlainString());
        if (BooleanUtil.isFalse(user.getSandAccountOpen())
                && (ObjectUtil.isNull(hfExt) || hfExt.getStatus() != AccountStatusEnum.SUCCESS)
                && (ObjectUtil.isNull(llUserExt) || llUserExt.getStatus() != AccountStatusEnum.SUCCESS)
                && (ObjectUtil.isNull(hnaExt) || hnaExt.getStatus() != AccountStatusEnum.SUCCESS)) {
            balance.setllwalletUnsettle(BigDecimal.ZERO);
            balance.setLlFrozenBal(BigDecimal.ZERO);
            balance.setLlAvailableBal(BigDecimal.ZERO);
            balance.setHfAvailableBal(BigDecimal.ZERO);
            balance.setHfFrozenBal(BigDecimal.ZERO);
            balance.setHnaAvailableBal("0.00");
            balance.setAvailableBal(BigDecimal.ZERO);
            balance.setFrozenBal(BigDecimal.ZERO);
            return Result.success(balance);
        }

        if (BooleanUtil.isTrue(user.getSandAccountOpen())) {
            balance = sandAccountHelper.getBalance(user);
        }
        if ((ObjectUtil.isNotNull(hfExt) && hfExt.getStatus() == AccountStatusEnum.SUCCESS)) {
            JSONObject jsonObject = payOrderService.HfBalance(user);
            balance.setHfAvailableBal(jsonObject.getBigDecimal("balance"));
            balance.setHfFrozenBal(jsonObject.getBigDecimal("freeze_balance"));
        }
        if ((ObjectUtil.isNotNull(llUserExt) && llUserExt.getStatus() == AccountStatusEnum.SUCCESS)) {
            JSONObject llbalance = llPayHelper.getBalanceSpecial(llUserExt);
            balance.setLlAvailableBal(llbalance.getBigDecimal("amt_balaval"));
            balance.setLlFrozenBal(llbalance.getBigDecimal("amt_balfrz"));
            balance.setllwalletUnsettle(llbalance.getBigDecimal("amt_unsettle"));
        }
        if ((ObjectUtil.isNotNull(hnaExt) && hnaExt.getStatus() == AccountStatusEnum.SUCCESS)) {
            JSONObject jsonObject = userHnaExtService.userInfo(user);
            String bal = jsonObject.getString("balAmount");
            if ("0".equals(bal)) {
                balance.setHnaAvailableBal("0.00");
            } else {
                BigDecimal bala = new BigDecimal(bal);
                balance.setHnaAvailableBal(bala.subtract(sandWithdrawRecordDao.sumWithdrawing4Hna(user.getId())).toString());
            }
        }
        return Result.success(balance);
    }

    @ApiOperation(value = "用户钱包开通列表", notes = "用户钱包开通列表", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/userWalletOpenList", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result<List<WalletChannelEnum>> userWalletOpenList() {
        UserInfo user = UserPool.getUser();
        List<WalletChannelEnum> walletChannelList = Lists.newArrayList();
        if (BooleanUtil.isTrue(user.getSandAccountOpen())) {
            walletChannelList.add(WalletChannelEnum.SAND);
        }
//        UserHfExt userHfExt = userHfExtDao.findByUserId(user.getId());
//        if (ObjectUtil.isNotNull(userHfExt) && userHfExt.getStatus() == AccountStatusEnum.SUCCESS) {
//            walletChannelList.add(WalletChannelEnum.HF);
//        }
        LlUserExt llUserExt = llUserExtService.getByUserId(user.getId());
        if (ObjectUtil.isNotNull(llUserExt) && llUserExt.getStatus() == AccountStatusEnum.SUCCESS) {
            walletChannelList.add(WalletChannelEnum.LL);
        }
        UserHnaExt userHnaExt = userHnaExtDao.getByUserId(user.getId());
        if (ObjectUtil.isNotNull(userHnaExt) && userHnaExt.getStatus() == AccountStatusEnum.SUCCESS) {
            walletChannelList.add(WalletChannelEnum.HNA);
        }
        return Result.success(walletChannelList);
    }


    @ApiOperation(value = "转账到提现钱包", notes = "转账到提现钱包", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/transfer", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result transfer(@RequestBody @Valid AmountRequest request) {
        UserInfo user = UserPool.getUser();
        if (request.getChannel() == null) {
            request.setChannel(WalletChannelEnum.SAND);
        }
        switch (request.getChannel()) {
            case SAND:
//                return Result.fail("衫德通道升级中，请选择其他通道进行提现");

                if (BooleanUtil.isFalse(user.getSandAccountOpen())) {
                    return Result.fail("您尚未完成衫德开户");
                }

                if (BooleanUtil.isFalse(user.getSandFaceVerify())) {
                    return Result.fail("您尚未完成人脸识别");
                }
                break;
            case HF:
                return Result.fail("汇付通道正在升级，请您暂时选择其他通道。");

//                UserHfExt userHfExt = userHfExtDao.findByUserId(user.getId());
//                if (ObjectUtil.isNull(userHfExt) || userHfExt.getStatus() != AccountStatusEnum.SUCCESS) {
//                    return Result.fail("您尚未完成汇付开户");
//                }
//                break;
            case LL:
                LlUserExt llUserExt = llUserExtService.getByUserId(user.getId());
                if (ObjectUtil.isNull(llUserExt) || llUserExt.getStatus() != AccountStatusEnum.SUCCESS) {
                    return Result.fail("您尚未完成连连开户");
                }
                break;
            case HNA:
                UserHnaExt userHnaExt = userHnaExtDao.getByUserId(user.getId());
                if (ObjectUtil.isNull(userHnaExt) || userHnaExt.getStatus() != AccountStatusEnum.SUCCESS) {
                    return Result.fail("您尚未完成新生开户");
                }
                break;
        }
        RLock lock = redisson.getLock(RedisKeyEnum.WITHDRAW_LOCK.getKey() + user.getId());
        try {
            boolean res = lock.tryLock(30, TimeUnit.SECONDS);
            if (res) {
                SandTransferRecord sandTransferRecord = sandTransferRecordService.transfer(user, request.getAmount(), request.getChannel());
//        sandAccountHelper.transfer(user,sandTransferRecord);  不自动转账
            } else {
                return Result.fail(ErrorCode.LATER_TRY);
            }
        } catch (InterruptedException e) {
            return Result.fail("当前人数过多，请稍后再试");
        } finally {
            lock.unlock();
        }
        return Result.success();
    }


    @ApiOperation(value = "转账列表", notes = "转账列表", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/transferPage", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result<SandTransferRecordVO> transferPage(@RequestBody @Valid TransferPageRequest request) {
        UserInfo user = UserPool.getUser();
        return PageResult.success(sandTransferRecordService.getPage(user.getId(), request.getQueryTime(), request.getPageNo(), request.getPageSize()), SandTransferRecordVO.class);
    }

    @ApiOperation(value = "衫德钱包充值", notes = "衫德钱包充值", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/sandRecharge", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result<String> sandRecharge(@RequestBody @Valid SandRegRequest request) {
        UserInfo user = UserPool.getUser();
        if (!user.getSandAccountOpen()) {
            return Result.fail("衫德账户尚未开户");
        }
        WithdrawBankCard withdrawBankCard = withdrawBankCardDao.getById(request.getCardId());
        if (ObjectUtil.isNull(withdrawBankCard) || withdrawBankCard.getUserId().longValue() != user.getId().longValue() || withdrawBankCard.getChannel() != WalletChannelEnum.SAND) {
            return Result.fail(ErrorCode.NOT_FOUND_BANK_CARD);
        }
        return Result.success(sandAccountHelper.recharge(user, request.getAmount(), withdrawBankCard.getRelatedCardNo()));
    }

    @ApiOperation(value = "全部支付渠道", notes = "全部支付渠道", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/allPayChannel", produces = MediaType.APPLICATION_JSON_VALUE)
    public Result<List<WalletChannelEnum>> allPayChannel() {
        return Result.success(WalletChannelEnum.getList());
    }

    @ApiOperation(value = "设置支付密码", notes = "设置支付密码", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/setPwd", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result<String> setPwd() {
        UserInfo user = UserPool.getUser();
        if (BooleanUtil.isFalse(user.getSandAccountOpen())) {
            return Result.fail("您尚未完成开户");
        }

        if (BooleanUtil.isFalse(user.getSandFaceVerify())) {
            return Result.fail("您尚未完成人脸识别");
        }
        return Result.success(sandAccountHelper.payPwd(user));
    }

    @ApiOperation(value = "设置支付密码H5", notes = "设置支付密码H5", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/setPwdH5", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result<String> setPwdH5() {
        UserInfo user = UserPool.getUser();
        if (BooleanUtil.isFalse(user.getSandAccountOpen())) {
            return Result.fail("您尚未完成开户");
        }

        if (BooleanUtil.isFalse(user.getSandFaceVerify())) {
            return Result.fail("您尚未完成人脸识别");
        }
        return Result.success(sandAccountHelper.payPwdH5(user));
    }


    @ApiOperation(value = "提现记录", notes = "提现记录", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/withdrawRecord", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public PageResult<SandWithdrawRecordVO> withdrawRecord(@RequestBody @Valid TransferPageRequest request) {
        UserInfo user = UserPool.getUser();

        Page page = sandWithdrawRecordDao.getPage(user.getId(), request.getQueryTime(), request.getChannel(), request.getPageNo(), request.getPageSize());
        List<SandWithdrawRecordVO> result = Lists.newArrayList();
        for (Object record : page.getRecords()) {
            SandWithdrawRecord r = (SandWithdrawRecord) record;
            SandWithdrawRecordVO vo = BeanUtil.toBeanIgnoreError(r, SandWithdrawRecordVO.class);
            vo.setAmount(r.getAmount().toPlainString());
            vo.setRealAmount(r.getRealAmount().toPlainString());
            vo.setFeeAmount(r.getFeeAmount().toPlainString());
            vo.setChannel(r.getChannel());
            vo.setCreateTime(DateUtil.formatDateTime(r.getCreateTime()));
            result.add(vo);
        }
        page.setRecords(result);
        return PageResult.success(page);
    }


    @ApiOperation(value = "提现到银行卡", notes = "提现到银行卡", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/withDraw", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result withDraw(@RequestBody @Valid WithdrawRequest request) {
        UserInfo user = UserPool.getUser();
        if (BooleanUtil.isFalse(user.getSandAccountOpen())) {
            return PageResult.fail("您尚未完成开户");
        }
        if (BooleanUtil.isFalse(user.getSandFaceVerify())) {
            return Result.fail("您尚未完成人脸识别");
        }
        if (BooleanUtil.isFalse(user.getSandPayPwd())) {
            return Result.fail("您尚未设置支密码");
        }
        WithdrawBankCard withdrawBankCard = withdrawBankCardDao.getById(request.getWithdrawBankId());
        if (ObjectUtil.isNull(withdrawBankCard) || BooleanUtil.isFalse(withdrawBankCard.getStatus()) || withdrawBankCard.getUserId().longValue() != user.getId().longValue() || withdrawBankCard.getChannel() != WalletChannelEnum.SAND) {
            return Result.fail("未找到银行卡");
        }

        BalanceVO balance = sandAccountHelper.getBalance(user);
        if (Convert.toBigDecimal(balance.getAvailableBal()).compareTo(request.getAmount()) < 0) {
            return Result.fail(ErrorCode.BALANCE_NO_ENOUGH);
        }
        String minimumWithdrawalAmountString = staticDataDao.getByType("minimum_withdrawal_amount").getValue();
        if (new BigDecimal(minimumWithdrawalAmountString).compareTo(request.getAmount()) > 0) {
            return Result.fail("提现金额不能小于" + minimumWithdrawalAmountString + "元");
        }
        String info = sandAccountHelper.withDraw(user, withdrawBankCard, request.getAmount());
        Map map = new HashedMap();
        map.put("url", info);
        return Result.success(map);
    }

    @ApiOperation(value = "提现回调通知", notes = "提现回调通知", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/withdraw/notify")
//    @ApiIgnore
    @WithoutSign
    public String withdrawNotify(PayBackRequest request) {
        String url = UriUtils.decode(request.getData(), StandardCharsets.UTF_8);
        JSONObject data = JSON.parseObject(url);
        if (StrUtil.equals(data.getString("respCode"), "00000")) {
            if (StrUtil.equals(data.getString("orderStatus"), "00")) {
                sandWithdrawRecordDao.success(data.getString("orderNo"));
            } else {
                sandWithdrawRecordDao.fail(data.getString("orderNo"), data.getString("respMsg"));
            }
        } else {
            sandWithdrawRecordDao.fail(data.getString("orderNo"), data.getString("respMsg"));
            log.warn("withdraw notify fail:{}", data);
        }
        return "respCode=000000";
    }

    @ApiOperation(value = "注销通知", notes = "注销通知", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/cancel/notify")
    @ApiIgnore
    @WithoutSign
    public String cancelNotify(PayBackRequest request) {
        log.info("注销原始数据:{}", JSON.toJSON(request));
        String url = UriUtils.decode(request.getData(), StandardCharsets.UTF_8);
        log.info("注销解析数据:{}", url);
        JSONObject data = JSON.parseObject(url);
        log.info("注销通知:{}", data);
        if (StrUtil.equals(data.getString("respCode"), "00000")) {
            UserInfo user = userInfoDao.getBySandWithUUid(data.getString("bizUserNo"));
//            user.setSandAccountOpen(false);
//            user.setSandFaceVerify(false);
//            user.setSandPayPwd(false);
//            user.updateById();
            userInfoDao.updateSandInfo(user.getId(), false, false, false);
        } else {
            log.warn("cancel notify fail:{}", data);
        }
        return "respCode=000000";
    }


    @ApiOperation(value = "人脸识别通知", notes = "人脸识别通知", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/protocol/notify")
    @ApiIgnore
    @WithoutSign
    public String protocolNotify(PayBackRequest request) {
        String url = UriUtils.decode(request.getData(), StandardCharsets.UTF_8);
        JSONObject data = JSON.parseObject(url);
        if (StrUtil.equals(data.getString("respCode"), "00000")) {
            UserInfo user = userInfoDao.getBySandWithUUid(data.getString("bizUserNo"));
            userInfoDao.sandFaceVerify(user.getId());
        } else {
            log.warn("protocol notify fail:{}", data);
        }
        return "respCode=000000";
    }


    @ApiOperation(value = "设置密码通知", notes = "人脸识别通知", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/pwd/notify")
    @ApiIgnore
    @WithoutSign
    public String pwdNotify(PayBackRequest request) {
        String url = UriUtils.decode(request.getData(), StandardCharsets.UTF_8);
        JSONObject data = JSON.parseObject(url);
        if (StrUtil.equals(data.getString("respCode"), "00000")) {
            UserInfo user = userInfoDao.getBySandWithUUid(data.getString("bizUserNo"));
            userInfoDao.sandPwd(user.getId());
        } else {
            log.warn("pwd notify fail:{}", data);
        }
        return "respCode=000000";
    }

    @ApiOperation(value = "用户是否开通钱包", notes = "用户是否开通杉德钱包", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/isOpenWallet", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result<Map> isOpenWallet() {
        Map map = new HashedMap();
        long userId = UserPool.getUser().getId();
        map.put("isOpenWallet", UserPool.getUser().getSandAccountOpen());
        UserHfExt userHfExt = userHfExtDao.findByUserId(userId);
        map.put("isHfOpenWallet", ObjectUtil.isNotNull(userHfExt) && userHfExt.getStatus() == AccountStatusEnum.SUCCESS);
        map.put("isFaceVerify", UserPool.getUser().getSandFaceVerify());
        map.put("isPayPwd", UserPool.getUser().getSandPayPwd());
        LlUserExt llUserExt = llUserExtService.getByUserId(userId);
        if (ObjectUtil.isNull(llUserExt)) {
            map.put("isLlOpenWallet", AccountStatusEnum.NO_OPEN);
        } else {
            map.put("isLlOpenWallet", llUserExt.getStatus());
            map.put("llRemark", llUserExt.getRemark());
        }
        UserHnaExt hnaExt = userHnaExtDao.getByUserId(userId);
        map.put("isHnaOpenWallet", ObjectUtil.isNotNull(hnaExt) && Objects.equals(hnaExt.getStatus(), AccountStatusEnum.SUCCESS));
        return Result.success(map);
    }


}


